package pe.com.casadesign.dao.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
import org.springframework.stereotype.Repository;

import pe.com.casadesign.dao.InventarioDAO;
import pe.com.casadesign.domain.Bulto;
import pe.com.casadesign.domain.Componente;
import pe.com.casadesign.domain.Inventario;
import pe.com.casadesign.domain.Item;
import pe.com.casadesign.domain.ItemComponente;
import pe.com.casadesign.domain.LineaGuia;
import pe.com.casadesign.domain.LineaInventario;
import pe.com.casadesign.domain.LineaInventarioBulto;
import pe.com.casadesign.domain.LineaOrdenCompra;
import pe.com.casadesign.domain.ListaInventario;
import pe.com.casadesign.domain.ListaItemComponente;
import pe.com.casadesign.domain.ListaLineaGuia;
import pe.com.casadesign.domain.ListaLineaInventarioBulto;
import pe.com.casadesign.domain.Modulo;
import pe.com.casadesign.domain.Moneda;
import pe.com.casadesign.domain.Producto;
import pe.com.casadesign.domain.Proveedor;
import pe.com.casadesign.domain.Rol;
import pe.com.casadesign.domain.Tienda;
import pe.com.casadesign.domain.Usuario;


/**
 * Implementacion de InventarioDAO.
 * 
 * @author Pedro Vera
 * 
 */
@Repository
public class InventarioDAOImpl implements InventarioDAO {
	private static final Logger logger = LoggerFactory.getLogger(InventarioDAOImpl.class);
	
	// Nombre Procedimientos Almacenados
	private static String SP_OBTENER_INVENTARIO = "SP_OBTENER_INVENTARIO";
	private static String SP_REGISTRAR_INVENTARIO = "SP_REGISTRAR_INVENTARIO";
	
	private static String SP_REGISTRAR_DET_INVENTARIO = "SP_REGISTRAR_DET_INVENTARIO";
	private static String SP_VALIDAR_INVENTARIO_ITEM = "SP_VALIDAR_INVENTARIO_ITEM";
	private static String SP_MODIFICAR_INVENTARIO = "SP_MODIFICAR_INVENTARIO";
	private static String SP_LISTAR_INVENTARIO = "SP_LISTAR_INVENTARIO";
	private static String SP_ACTUALIZAR_ESTADO_INVENTARIO = "SP_ACTUALIZAR_ESTADO_INVENTARIO";
	
	private static String SP_REGISTRAR_DET_INVBULTO = "SP_REGISTRAR_DET_INVBULTO";
	private static String SP_VALIDAR_INVENTARIO_BULTO = "SP_VALIDAR_INVENTARIO_BULTO";

	
		
	// Parametros de Entrada
	private static String PARAM_CODINVENTARIO = "p_codinventario";
	private static String PARAM_CODTIENDA = "p_codtienda";
	private static String PARAM_TIPO = "p_tipo";
	private static String PARAM_NROREFERENCIA = "p_nroreferencia";
	private static String PARAM_OBSERVACION = "p_observacion";
	private static String PARAM_CODUSUARIO = "p_codusuario";
	private static String PARAM_ESTADO = "p_estado";
	
	private static String PARAM_DET_CODPRODUCTO = "p_codproducto";
	private static String PARAM_DET_CODITEM = "p_coditem";
	private static String PARAM_DET_CANTIDAD = "p_cantidad";
	private static String PARAM_DET_COMPONENTE = "p_componente";
	
	private static String PARAM_DETBULTO_CODBULTO = "p_codbulto";
	private static String PARAM_DETBULTO_CODITEM = "p_coditem";
	private static String PARAM_DETBULTO_CODCOMPONENTE = "p_componente";
	
	private static String PARAM_ITEM_CODIFICACION = "p_codificacion"; 
	
	// Parametros de Salida
	private static String CODINVENTARIO = "CODINVENTARIO";
	private static String CODTIENDA = "CODTIENDA";
	private static String TIPO = "TIPO";
	private static String NROREFERENCIA = "NROREFERENCIA";
	private static String OBSERVACION = "OBSERVACION";
	private static String CODUSUARIO = "CODUSUARIO";
	private static String FECHAREGISTRO = "FECHAREGISTRO";
	private static String ESTADO = "ESTADO";
	
	private static String TIENDA_NOMBRE = "NOMBRE";
	
	private static String USUARIO_NOMBRESYAPELLIDOS = "NOMBRESYAPELLIDOS";
	
	private static String CONTAR = "CONTAR";
	
	private static String ITEM_CODITEM = "CODITEM";
	private static String ITEM_CODPRODUCTO = "CODPRODUCTO";
	private static String ITEM_CODPRODUCTOPROVEEDOR = "CODPRODUCTOPROVEEDOR";
	private static String ITEM_CODIFICACION = "CODIFICACION"; 
	private static String ITEM_CODPROVEEDOR = "CODPROVEEDOR"; 
	private static String ITEM_ORIGEN = "ORIGEN"; 
	private static String ITEM_PROPIEDADES = "PROPIEDADES";
	private static String ITEM_PRECIOCOMPRA = "PRECIOCOMPRA"; 
	private static String ITEM_CODMONEDA = "CODMONEDA"; 
	private static String ITEM_CODOC = "CODOC"; 
	private static String ITEM_NROLINEA = "NROLINEA";
	private static String ITEM_CODTIENDA = "CODTIENDA";
	private static String ITEM_ESTADO = "ESTADO"; 
	private static String ITEM_FECHAREGISTRO = "FECHAREGISTRO";
	
	private static String ITEM_CODCOMPONENTE = "CODCOMPONENTE";
	
	private static String INVBULTO_CODBULTO = "CODBULTO";
	private static String INVBULTO_CODIFICACION = "CODIFICACION";
	private static String INVBULTO_FECHAREGISTRO = "FECHAREGISTRO";
	private static String INVBULTO_CODINVENTARIO = "CODINVENTARIO";
	private static String INVBULTO_COMPONENTE = "COMPONENTE";
	private static String INVBULTO_CODITEM = "CODITEM";
	private static String INVBULTO_CODUSUARIO = "CODUSUARIO";
	
	private static String INV_CODPRODUCTO = "CODPRODUCTO";
	private static String INV_CODIFICACION = "CODIFICACION";
	private static String INV_FECHAREGISTRO = "FECHAREGISTRO";
	private static String INV_CODINVENTARIO = "CODINVENTARIO";
	private static String INV_COMPONENTE = "COMPONENTE";
	private static String INV_CODITEM = "CODITEM";
	private static String INV_CODUSUARIO = "CODUSUARIO";
	
	
	private static String PRODUCTO_DESCRIPCION = "DESCRIPCION";
	
	private static String LISTADO = "LISTADO";
	
	private static String TOTAL_FILAS_AFECTADAS = "#update-count-1";
	
	private JdbcTemplate jdbcTemplate;

	@Autowired
    public void setDataSource(DataSource dataSource)
    {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
	
	@Override
	public Inventario obtenerInventario(Inventario inventario) {
		logger.info("obtenerInventario");

		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_OBTENER_INVENTARIO).
	    						  returningResultSet(LISTADO, new RowMapper<Inventario>(){
									@Override
									public Inventario mapRow(final ResultSet rs, final int numRow) throws SQLException
								    {
								        final Inventario inventario = new Inventario();
								        inventario.setCodInventario(rs.getInt(CODINVENTARIO));
								        
								        Tienda tienda =  new Tienda();
								        tienda.setCodigo(rs.getInt(CODTIENDA));
								        tienda.setNombre(rs.getString(TIENDA_NOMBRE));
								        inventario.setTienda(tienda);
								        
								        inventario.setTipo(rs.getString(TIPO));
								        inventario.setNroReferencia(rs.getString(NROREFERENCIA));

								        inventario.setObservacion(rs.getString(OBSERVACION));
								        						        
								        Usuario usuario = new Usuario();
								        usuario.setCodUsuario(rs.getInt(CODUSUARIO));
								        usuario.setNombresyApellidos(rs.getString(USUARIO_NOMBRESYAPELLIDOS));
								        inventario.setUsuario(usuario);
								        
								        inventario.setFechaRegistro(rs.getDate(FECHAREGISTRO).toString());
								        inventario.setEstado(rs.getString(ESTADO));
								        
								        return inventario;
								    }
	    						  }
								 );

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODINVENTARIO, inventario.getCodInventario())
	    								.addValue(PARAM_CODTIENDA, inventario.getTienda().getCodigo());

	    // Establecer parametros y ejecutar SP
        Map<String,Object> data = llamarSP.execute(parametros);

        // Obteniendo lista generada de ejecutar SP
 		@SuppressWarnings("unchecked")
 		List<Inventario> listaInventario= (List<Inventario>)data.get(LISTADO);
         
 		// Declarando objeto inventario Obtenido
 		Inventario inventarioObtenido = null;
 		
 		if (logger.isDebugEnabled() && listaInventario != null)
        {
            logger.debug("size=" + listaInventario.size());
        }
 		
 		if (listaInventario != null && listaInventario.size()>0){
 			// Obteniendo el primer elemento de la lista
 			inventarioObtenido = listaInventario.get(0);
 		}
 		
        return inventarioObtenido;
	}

	@Override
	public boolean registrarInventario(Inventario inventario) {
		logger.info("registrarInventario");
		
		int resultado = 0;
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate)
	    							  .withProcedureName(SP_REGISTRAR_INVENTARIO);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODTIENDA, inventario.getTienda().getCodigo())
	    								.addValue(PARAM_TIPO, inventario.getTipo())
	    								.addValue(PARAM_NROREFERENCIA, inventario.getNroReferencia())
	    								.addValue(PARAM_OBSERVACION, inventario.getObservacion())
	    								.addValue(PARAM_ESTADO, inventario.getEstado())
	    								.addValue(PARAM_CODUSUARIO, inventario.getUsuario().getCodUsuario());
    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    resultado = (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	    
	    logger.debug("codigo generado:" + data.get(PARAM_CODINVENTARIO));

	    // Obteniendo codigo de inventario
	    int codigoInventario = (Integer)data.get(PARAM_CODINVENTARIO);

	    // Estableciendo codigo de orden de compra generada
	    inventario.setCodInventario(codigoInventario);
	    
	    return resultado > 0;
	}
	
	public boolean registrarDetalleInventario(LineaInventario lineaInventario) {
		logger.info("registrardetInventario");
		
		int resultado = 0;
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate)
	    							  .withProcedureName(SP_REGISTRAR_DET_INVENTARIO);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
											.addValue(PARAM_CODINVENTARIO,lineaInventario.getInventario().getCodInventario())
											.addValue(PARAM_DET_CODPRODUCTO, lineaInventario.getProducto().getCodigo())
											.addValue(PARAM_DET_CODITEM, lineaInventario.getItem().getCodItem())
											.addValue(PARAM_DET_COMPONENTE, lineaInventario.getComponente())
											.addValue(PARAM_CODUSUARIO, lineaInventario.getUsuario().getCodUsuario())
											.addValue(PARAM_ITEM_CODIFICACION, lineaInventario.getCodificacion());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    resultado = (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	        
	    return resultado > 0;
		
	}
	
	public LineaInventario validarDetalleInventario(LineaInventario lineaInventario){
		logger.info("validarDetalleInventario");
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_VALIDAR_INVENTARIO_ITEM).
								  returningResultSet(LISTADO, new RowMapper<LineaInventario>(){
									@Override
									public LineaInventario mapRow(final ResultSet rs, final int numRow) throws SQLException
								    {
								        
										final LineaInventario lineaInventario = new LineaInventario();
								        lineaInventario.setCodificacion(rs.getString(INV_CODIFICACION));
								        lineaInventario.setFechaRegistro(rs.getDate(INV_FECHAREGISTRO).toString());
								        lineaInventario.setComponente(rs.getInt(INV_COMPONENTE));
								        
								        Inventario inventario = new Inventario();
								        inventario.setCodInventario(rs.getInt(INV_CODINVENTARIO));
								        lineaInventario.setInventario(inventario);
								        							        								  
								        Producto producto = new Producto();
								        producto.setCodigo(rs.getInt(INV_CODPRODUCTO));
								        lineaInventario.setProducto(producto);						        
								     								        
								        Item item = new Item();
								        item.setCodItem(rs.getInt(INV_CODITEM));
								        lineaInventario.setItem(item);
								        
								        Usuario usuario = new Usuario();
								        usuario.setCodUsuario(rs.getInt(INV_CODUSUARIO));
								        lineaInventario.setUsuario(usuario);
								        
								        return lineaInventario;
								        
								    }
								  }
								);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_ITEM_CODIFICACION, lineaInventario.getCodificacion())
	    								.addValue(PARAM_CODINVENTARIO, lineaInventario.getInventario().getCodInventario());

	    // Establecer parametros y ejecutar SP
        Map<String,Object> data = llamarSP.execute(parametros);
               
        // Obteniendo lista generada de ejecutar SP
		@SuppressWarnings("unchecked")
		List<LineaInventario> listaLineaInventario = (List<LineaInventario>)data.get(LISTADO);
        	
		// Declarando objeto item Obtenido
		LineaInventario lineaInventarioObtenido = null;
		
		if (listaLineaInventario != null && listaLineaInventario.size()>0){
			// Obteniendo el primer elemento de la lista de item
			lineaInventarioObtenido = listaLineaInventario.get(0);
		}
        
		return lineaInventarioObtenido;
	}
	
	public boolean registrarDetalleInventarioBulto(LineaInventarioBulto lineaInventarioBulto) {
		logger.info("registrardetInventarioBulto");
		
		int resultado = 0;
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate)
	    							  .withProcedureName(SP_REGISTRAR_DET_INVBULTO);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
											.addValue(PARAM_CODINVENTARIO,lineaInventarioBulto.getInventario().getCodInventario())
											.addValue(PARAM_DETBULTO_CODBULTO, lineaInventarioBulto.getBulto().getCodBulto())
											.addValue(PARAM_DETBULTO_CODITEM, lineaInventarioBulto.getItem().getCodItem())
											.addValue(PARAM_DETBULTO_CODCOMPONENTE, lineaInventarioBulto.getComponente())
											.addValue(PARAM_CODUSUARIO, lineaInventarioBulto.getUsuario().getCodUsuario())
											.addValue(PARAM_ITEM_CODIFICACION, lineaInventarioBulto.getCodificacion());
    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    resultado = (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	        
	    return resultado > 0;
		
	}
	
	public LineaInventarioBulto validarDetalleInventarioBulto(LineaInventarioBulto lineaInventarioBulto){
		logger.info("validarDetalleInventarioBulto");
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_VALIDAR_INVENTARIO_BULTO).
								  returningResultSet(LISTADO, new RowMapper<LineaInventarioBulto>(){
									@Override
									public LineaInventarioBulto mapRow(final ResultSet rs, final int numRow) throws SQLException
								    {
								        
										final LineaInventarioBulto lineaInventarioBulto = new LineaInventarioBulto();
								        lineaInventarioBulto.setCodificacion(rs.getString(INVBULTO_CODIFICACION));
								        lineaInventarioBulto.setFechaRegistro(rs.getDate(INVBULTO_FECHAREGISTRO).toString());
								        lineaInventarioBulto.setComponente(rs.getInt(INVBULTO_COMPONENTE));
								        
								        Inventario inventario = new Inventario();
								        inventario.setCodInventario(rs.getInt(INVBULTO_CODINVENTARIO));
								        lineaInventarioBulto.setInventario(inventario);
								        
								        Bulto bulto = new Bulto();
								        bulto.setCodBulto(rs.getInt(INVBULTO_CODBULTO));
								        lineaInventarioBulto.setBulto(bulto);						        
								     								        
								        Item item = new Item();
								        item.setCodItem(rs.getInt(INVBULTO_CODITEM));
								        lineaInventarioBulto.setItem(item);
								        
								        Usuario usuario = new Usuario();
								        usuario.setCodUsuario(rs.getInt(INVBULTO_CODUSUARIO));
								        lineaInventarioBulto.setUsuario(usuario);
								        
								        return lineaInventarioBulto;
								        
								    }
								  }
								);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_ITEM_CODIFICACION, lineaInventarioBulto.getCodificacion())
	    								.addValue(PARAM_CODINVENTARIO, lineaInventarioBulto.getInventario().getCodInventario());

	    // Establecer parametros y ejecutar SP
        Map<String,Object> data = llamarSP.execute(parametros);
               
        // Obteniendo lista generada de ejecutar SP
		@SuppressWarnings("unchecked")
		List<LineaInventarioBulto> listaLineaInventarioBulto = (List<LineaInventarioBulto>)data.get(LISTADO);
        	
		// Declarando objeto item Obtenido
		LineaInventarioBulto lineaInventarioBultoObtenido = null;
		
		if (listaLineaInventarioBulto != null && listaLineaInventarioBulto.size()>0){
			// Obteniendo el primer elemento de la lista de item
			lineaInventarioBultoObtenido = listaLineaInventarioBulto.get(0);
		}
        
		return lineaInventarioBultoObtenido;
	}
	
	
	public int modificarInventario(Inventario inventario){
		logger.info("modificarInventario");
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_MODIFICAR_INVENTARIO);
	    
	   // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODINVENTARIO, inventario.getCodInventario())
	    								.addValue(PARAM_CODTIENDA, inventario.getTienda().getCodigo())
	    								.addValue(PARAM_TIPO, inventario.getTipo())
	    								.addValue(PARAM_OBSERVACION, inventario.getObservacion())
	    								.addValue(PARAM_NROREFERENCIA, inventario.getNroReferencia())
	    								.addValue(PARAM_CODUSUARIO, inventario.getUsuario().getCodUsuario())  								
	    								.addValue(PARAM_ESTADO, inventario.getEstado());
	        
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    int totalRegistrosAfectado = (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	        
	    return totalRegistrosAfectado;
	}
	
	@Override
	public ListaInventario listarInventario (Inventario inventario)
	{
		logger.info("listarInventario");

		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_LISTAR_INVENTARIO).
	    						  returningResultSet(LISTADO, new RowMapper<Inventario>(){
									@Override
									public Inventario mapRow(final ResultSet rs, final int numRow) throws SQLException
								    {
								        final Inventario inventario = new Inventario();
								        inventario.setCodInventario(rs.getInt(CODINVENTARIO));
								        
								        Tienda tienda =  new Tienda();
								        tienda.setCodigo(rs.getInt(CODTIENDA));
								        tienda.setNombre(rs.getString(TIENDA_NOMBRE));
								        inventario.setTienda(tienda);
									       							        
								        inventario.setTipo(rs.getString(TIPO));
								        inventario.setNroReferencia(rs.getString(NROREFERENCIA));
								        inventario.setObservacion(rs.getString(OBSERVACION));
								        
								        Usuario usuario = new Usuario();
								        usuario.setCodUsuario(rs.getInt(CODUSUARIO));
								        usuario.setNombresyApellidos(rs.getString(USUARIO_NOMBRESYAPELLIDOS));
								        inventario.setUsuario(usuario);
								        
													        
								        inventario.setEstado(rs.getString(ESTADO));
								        inventario.setFechaRegistro(rs.getDate(FECHAREGISTRO).toString());
								       
								        return inventario;
						
								        
								    }
	    						  }
								);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODTIENDA, inventario.getTienda().getCodigo())
	    								.addValue(PARAM_ESTADO, inventario.getEstado()); 

	    // Establecer parametros y ejecutar SP
        Map<String,Object> data = llamarSP.execute(parametros);

        // Obteniendo lista generada de ejecutar SP
		@SuppressWarnings("unchecked")
		List<Inventario> listaInventario = (List<Inventario>)data.get(LISTADO);
        
		// Instanciando objeto ListaSolicitud
		ListaInventario listaInventarioResultado = new ListaInventario();
        // Estableciendo resultado al objeto listaSolicitudResultado
		listaInventarioResultado.setLista(listaInventario);
        
        if (logger.isDebugEnabled() && listaInventarioResultado != null)
        {
            logger.debug("size=" + listaInventarioResultado.size());
        }
        return listaInventarioResultado;
	}
	
	public int actualizarEstadoInventario(Inventario inventario){
		logger.info("actualizarEstadoInventario");
		
		// Instanciando variable para llamado de SP
	    SimpleJdbcCall llamarSP = new SimpleJdbcCall(jdbcTemplate).withProcedureName(SP_ACTUALIZAR_ESTADO_INVENTARIO);

	    // Estableciendo parametros de entrada al SP
	    SqlParameterSource parametros = new MapSqlParameterSource()
	    								.addValue(PARAM_CODINVENTARIO, inventario.getCodInventario())
	    								.addValue(PARAM_ESTADO, inventario.getEstado());
	    
	    // Establecer parametros y ejecutar SP
	    Map<String,Object> data = llamarSP.execute(parametros);
	    
	    // Obteniendo el total de filas afectadas al ejecutar SP
	    int totalRegistrosAfectado = (Integer) data.get(TOTAL_FILAS_AFECTADAS);
	        
	    return totalRegistrosAfectado;
	}
	
}
